package com.xxyf.service.imp;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xxyf.domain.PageParams;
import com.xxyf.domain.PageResult;
import com.xxyf.dto.Msg;
import com.xxyf.entity.Like;
import com.xxyf.entity.Message;
import com.xxyf.entity.Reply;
import com.xxyf.mapper.LikeMapper;
import com.xxyf.mapper.MessageMapper;
import com.xxyf.mapper.ReplyMapper;
import com.xxyf.service.MessageService;
import com.xxyf.tools.Code;
import com.xxyf.tools.Rest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author 小小怡飞
 * @Date 2023/3/2 13:18
 * @Version JDK 8
 */
@Service
public class MessageImp implements MessageService {
    static String LIKE = "like";
    @Autowired
    private MessageMapper mapper;
    @Autowired
    private ReplyMapper replyMapper;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private LikeMapper likeMapper;

    /**
     * 点赞
     * @param type
     * @param pid
     * @param userid
     * @return
     */
    @Override
    public Rest like(String type,Long pid, Long userid) {
        if (MSG.equals(type) && REPLY.equals(type)){
            return Rest.error("参数异常");
        }
        //拼接主键 使用redis 的Set 主键为留言id 值为userid
        String key = LIKE+":"+type+":"+pid;
        Long add = redisTemplate.opsForSet().add(key, userid);
        if (add==null){
            throw new RuntimeException("点赞错误");
        }
        return add>0L?Rest.succeed("点赞成功"):Rest.error("请勿重复点赞");
    }
    /**
     * 取消点赞功能点赞
     * @param type
     * @param pid
     * @param userid
     * @return
     */
    @Override
    public Rest notLike(String type,Long pid, Long userid) {
        if (MSG.equals(type) && REPLY.equals(type)){
            return Rest.error("参数异常");
        }
        String key = LIKE+":"+type+":"+pid;
        Long remove =null;
        try {
            remove = redisTemplate.opsForSet().remove(key,userid);
        }catch (Exception e){
            throw new RuntimeException("取消点赞错误");
        }

        if (remove==null){
            throw new RuntimeException("取消点赞错误");
        }
//        根据字段选择数据库进行删除
        if (MSG.equals(type)){
            LambdaUpdateWrapper<Like> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(Like::getUserid,userid).eq(Like::getMsgid,pid);
            likeMapper.delete(wrapper);
        } else if (REPLY.equals(type)) {
            LambdaUpdateWrapper<Like> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(Like::getUserid,userid).eq(Like::getReplyid,pid);
            likeMapper.delete(wrapper);
        }
        return remove>0L?Rest.succeed("取消点赞成功"):Rest.error("请勿重复取消点赞");
    }


    public static String MSG = "MSG";
    public static String REPLY = "REPLY";

    /**
     * 删除评论
     * @param type
     * @param id
     * @param userid
     * @return
     */
    @Transactional
    @Override
    public Rest delete(String type, Long id,Long userid) {

//        检查删除类型是回复还是发表
        if (MSG.equals(type)){
//            拼接sql更新数据库
            LambdaUpdateWrapper<Message> wrapper = new LambdaUpdateWrapper<>();
            wrapper.set(Message::getDeleted,1);
            wrapper.eq(Message::getId,id);
            wrapper.eq(Message::getUserid,userid);
            int delete = mapper.update(null,wrapper);
//            删除成功
            if (delete>0){
                LambdaUpdateWrapper<Reply> sonWrapper = new LambdaUpdateWrapper<>();
                sonWrapper.set(Reply::getDeleted,1);
                sonWrapper.eq(Reply::getMessageid,id);
//                这里不需要添加userid

                LambdaQueryWrapper<Reply> wrapper1 = new LambdaQueryWrapper<>();
                wrapper1.eq(Reply::getMessageid,id);
                wrapper1.select(Reply::getId);
                List<Reply> replies = replyMapper.selectList(wrapper1);
                int update = replyMapper.update(null, sonWrapper);
//                删除留言表缓存
                delCache(id, userid,MSG);
//                判断是否需要删除
                if (replies!=null && replies.size()>0 && update>0){
                    List<Long> collect = replies.stream().map(Reply::getId).collect(Collectors.toList());
                    collect.forEach(rid->{
                        //            删除回复表
                        delCache(rid, userid,REPLY);
                    });
                }
                return Rest.succeed("删除成功");
            }else {
//                无数据返回给前端
                return Rest.error("数据已被删除");

            }
        } else if (REPLY.equals(type)) {
            LambdaUpdateWrapper<Reply> sonWrapper = new LambdaUpdateWrapper<>();
            sonWrapper.set(Reply::getDeleted,1);
            sonWrapper.eq(Reply::getId,id);
//            这里得加要不给别人的删了
            sonWrapper.eq(Reply::getUserid,userid);
            int update = replyMapper.update(null, sonWrapper);
//            查询所有key
            if (update>0){
                delCache(id, userid,REPLY);
            }



            return update>0?Rest.succeed("删除成功"):Rest.error("数据已被删除");
        }
//        两个参数都不符合就错误
        return Rest.error("数据已被删除");
    }

    private void delCache(Long id, Long userid,String type) {

            LambdaUpdateWrapper<Like> likeWrapper = new LambdaUpdateWrapper<>();
//删除点赞记录
            if (Objects.equals(type, MSG)){
//                删除留言表
                Set<Object> members = redisTemplate.opsForSet().members(LIKE + ":" + MSG + ":" + "id");
                if (members!=null && members.size()>0){
                    List<Integer> collect = members.stream().map(x -> (Integer) x).collect(Collectors.toList());
                    likeWrapper.in(Like::getUserid,collect).eq(Like::getMsgid,id);
                }


            }else {
                Set<Object> members = redisTemplate.opsForSet().members(LIKE + ":" + REPLY + ":" + "id");
                if (members!=null && members.size()>0){
                    List<Integer> collect = members.stream().map(x -> (Integer) x).collect(Collectors.toList());
                    likeWrapper.in(Like::getUserid,collect).eq(Like::getReplyid,id);
                }
            }
            likeMapper.delete(likeWrapper);
            redisTemplate.delete(LIKE+":"+type+":"+id);


    }

    /**
     * 回复评论
     * @param reply
     * @return
     */
    @Transactional
    @Override
    public Rest insert(Reply reply) {
//        先获取当前时间戳

        long date = System.currentTimeMillis();
        Timestamp timestamp = new Timestamp(date);
        reply.setGtmCreate(timestamp);
        reply.setGtmModifide(timestamp);
//        直接插入即可如果缺少字段数据库会抛出异常
        int insert = replyMapper.insert(reply);
//        通知评论表下方有评论
        LambdaUpdateWrapper<Message> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Message::getId,reply.getMessageid());
        wrapper.set(Message::getExamine,1);
        mapper.update(null,wrapper);
//        初始化点赞与评论
        reply.setPraise(false);
        reply.setStar(0L);
        return insert>=0?Rest.succeed("回复成功",reply):Rest.error("回复异常");
    }

    /**
     * 留言表评论
     * @param message 表
     * @return
     */
    @Transactional
    @Override
    public Rest crate(Message message) {
        Date date = new Date();
        Timestamp timestamp = new Timestamp(date.getTime());
        message.setGtmCreate(timestamp);
        message.setGtmModifide(timestamp);
        int insert = mapper.insert(message);
        message.setPraise(false);
        message.setStar(0L);
        return insert>=0?Rest.succeed("评论成功",message):Rest.error("评论异常");
    }

    /**
     * 查询功能
     * @param pageParams
     * @return
     */
    @Override
    public Rest query(PageParams pageParams,Long userid) {
//        分页查询留言表
        Page<Message> objectPage = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());
        Page<Message> messagePage = mapper.selectPage(objectPage, null);
//获取结果集
        List<Message> records = messagePage.getRecords();
        if (records==null || records.size()==0){
            return Rest.error("无留言");
        }
        List<Msg> collect = records.stream().map(x -> {
//            首先判断是否有子回复

            if (x.getExamine() == 1) {
//                如果有子回复那么查询回复表
                LambdaQueryWrapper<Reply> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(Reply::getMessageid, x.getId());
//                wrapper.eq(Reply::getUserid, x.getUserid());
//                去redis里查询点赞数量
                Long size = redisTemplate.opsForSet().size(LIKE + ":"+MSG +":"+ x.getId());
                x.setStar(size);
//                判断是否点赞
                Boolean member = redisTemplate.opsForSet().isMember(LIKE + ":"+MSG +":"+ x.getId(), userid);
                x.setPraise(member);
                List<Reply> replies = replyMapper.selectList(wrapper);
                replies.forEach(reply -> {
                    //                去redis里查询点赞数量
                    Long replySize = redisTemplate.opsForSet().size(LIKE + ":"+REPLY +":"+ reply.getId());
                    reply.setStar(replySize);
                    //                判断是否点赞
                    Boolean replyMember = redisTemplate.opsForSet().isMember(LIKE + ":"+REPLY +":"+ reply.getId()
                            , userid);
                    reply.setPraise(replyMember);
                });
                return new Msg(x, replies);
            }else {
                Long size = redisTemplate.opsForSet().size(LIKE + ":"+MSG +":"+ x.getId());
                x.setStar(size);
                Boolean member = redisTemplate.opsForSet().isMember(LIKE + ":"+MSG +":"+ x.getId(), userid);
                x.setPraise(member);
            }
            return new Msg(x);
        }).collect(Collectors.toList());
        PageResult<Msg> msgPageResult = new PageResult<Msg>(
                collect,messagePage.getTotal(),messagePage.getCurrent(),messagePage.getSize()
        );

        return new Rest(msgPageResult);
    }
}
